/**
 * 类, 构造, this
 * 继承 抽象类
 * 接口
 * 属性封装
 * 泛型
 */

// 类, 构造, this
class Person {
    // 类属性
    static count: number = 10
    // 类成员
    name: string
    // 只读类成员
    readonly age: number

    // 构造函数
    constructor(name: string, age: number) {
        this.name = name
        this.age = age

        Person.count++
    }

    // 类成员
    speak(): void | never {
        console.log(`my name is ${this.name}, age is ${this.age}`)
    }

    static getCount(): number {
        return Person.count
    }
}

const p1: Person = new Person("rose", 30)
console.log(p1, Person.count)
console.log(Person.getCount())

class Dog {
    name: string
    age: number

    // 内存初始化(系统清理内存), 默认初始化(语言类型默认值),
    // 构造初始化(类成员初始值) -> 理解三种初始化时间, 目的
    constructor(name: string, age: number) {
        // console.log('calling constructor: 创建新实例时调用')
        this.name = name
        this.age = age
    }

    bark(): void | never {
        console.log(this.name, 'bark')
    }
}

const d1: Dog = new Dog('旺财', 2)
const d2: Dog = new Dog('大黄', 4)
const d3: Dog = new Dog('小黄', 1)
console.log(d1)
console.log(d2)
console.log(d3)


// 继承, 抽象类
;(function (): void | never {
    class Animal {
        name: string
        age: number

        constructor(name: string, age: number) {
            this.name = name
            this.age = age
        }

        speak(): void | never {
            console.log('animal speak')
        }
    }

    // 继承Animal
    class Dog extends Animal {
        // constructor(name: string, age: number) {
        //     super(name, age)
        // }

        speak(): void | never {
            console.log('dog speak')
        }
    }

    class Cat extends Animal {
        // 添加属性
        type: string

        constructor(name: string, age: number, type: string) {
            super(name, age)
            // 添加属性
            this.type = type
        }

        speak(): void | never {
            // super.speak() super 用来代替指向父类对象的内存部分
            console.log('cat speak')
        }

        //支持重载, 但是不支持重载
        //speak(a:number):number {}

        catchMouse() {
            console.log('抓老鼠')
        }
    }

    const d1 = new Dog('小黄', 30)
    console.log(d1)
    d1.speak()
    const c1: Dog = new Cat('小猫', 2, '狸花猫')
    console.log(c1)
    c1.speak()

    // 抽象类
    abstract class Walker {
        walk() {
        }
    }

    // 抽象类: 不允许实例化
    // const w:Walker = new Walker()
})()

// 接口: 都是抽象方法, js接口可以定义成员
interface Reader {
    read(): number
}

interface Comparable {
    compareTo(o: Comparable): number
}

// 接口和类型声明
type MyType = {
    name: string, age: number
}

interface MyType2 {
    name: string,
    age: number
}

// 接口可以多次定义, 取合并结果
interface MyType2 {
    speak(): void | never
}

// 接口实现
class Eagle implements Comparable, Reader {
    read(): number {
        return 0;
    }

    compareTo(o: Comparable): number {
        return 0;
    }

}

// 属性封装
// ts 支持 public private protected 访问修饰符
;(function (): void | never {
    enum Gender {
        MALE,
        FEMALE
    }

    // 封装保护
    class Person {
        private _name:string
        private _age: number
        private _gender: Gender
        constructor(name: string, age: number,
                    gender: Gender) {
            this._name = name
            this._age = age
            this._gender = gender
        }
        // typescript 属性读取和写入的方法
        // 实际访问的时候, 和直接读取属性一样, 不需要用方法调用语法
        get name(): string {
            return this._name;
        }
        set name(value: string) {
            this._name = value;
        }
    }
    
    const p1 = new Person('孙悟空', 2087, Gender.MALE)
    // 未封装, 属性可以被任意修改, 不安全, 大规模开发的不确定性太强了
    // 可维护性, 可扩展性降低
    p1.name = 'abc'
    // p1.age = 30
    console.log(p1)
})()



// 泛型
;(function(): void | never {
    // 执行时确定K具体是什么类型
    function fn<K>(a: K) : K{
        return a
    }

    // 指定泛型
    const k1 = fn<number>(1)
    const k2 = fn<string>('1')
    console.log(k1, k2)
    console.log(typeof k1, typeof k2)

    // 泛型边界限定  extends 上界  super 下界
    // <T extends Number>  <T super Number> 下边界

})()
